﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using CityLife.CityService;
using CityLife.Controls;
using CityLife.GameLogic;
using CityLife.Objects;
using Facebook.Schema;
using Facebook.Utility;

namespace CityLife
{



    public class CityHeart
    {

        private List<ICityElement> m_CityObjects;
        private CityLife.CityService.City m_City;
        //private double _CityInterval = 1;

        public double CityInterval = 1;





        #region Public properties
        public Canvas SplashLogin;

        public List<Car> Cars;
        public long UserID = 0;
        public Clock CityClock;
        public TextBlock SaveIndicator;
        public TextBlock CashView;
        public TextBlock PointsView;
        public TextBlock PopulationView;
        public Neighbours FriendsListbox;
        public ElementToolBar ElementInformation;
        public CityEditor CityEditor;
        public UserControl Page;

        public Dispatcher Dispatcher;

        public CityLife.CityService.City City
        {
            get { return m_City; }
            set { m_City = value; }
        }

        public CityCanvas CityCanvas { get; set; }
        public Canvas WindowCityCanvas { get; set; }

        public Dictionary<long, Neighbour> Neigbours { get; set; }
        public Dictionary<long, ICityDesign> NeigboursZones = new Dictionary<long, ICityDesign>();

        #endregion

        public System.Windows.Threading.DispatcherTimer ElementInformationTimer = new System.Windows.Threading.DispatcherTimer();
        public System.Windows.Threading.DispatcherTimer myDispatcherTimer = new System.Windows.Threading.DispatcherTimer();

        public CityHeart()
        {
            myDispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 10000); // 100 Milliseconds 
            myDispatcherTimer.Tick += new System.EventHandler(myDispatcherTimer_Tick);

            ElementInformationTimer.Interval = new TimeSpan(0, 0, 0, 0, 1000); // 100 Milliseconds 
            ElementInformationTimer.Tick += new EventHandler(ElementInformationTimer_Tick);
            ElementInformationTimer.Stop();
        }

        public void SetDirty()
        {

            myDispatcherTimer.Stop();

            myDispatcherTimer.Start();

        }


        #region Game function
        public bool Buy(ActiveTool activeTool)
        {
            int price = activeTool.info.Cost;

            int actualCash = (this.City.CityStatus.Cash - this.City.Budget.Spendings);
            //can i buy this?
            if (price > actualCash || actualCash < 1)
            {
                AlertWindow alert = new AlertWindow();
                alert.Title = "Need more cash?";
                alert.VerticalAlignment = VerticalAlignment.Center;
                alert.VerticalOffset = 150;
                alert.HorizontalOffset = 150;

                alert.Width = 250;
                alert.Height = 150;
                alert.DialogContent.Text = "You do not have enough money for this item.";

                alert.Show();
                return false; ;
            }

            // int startCash = this.City.CityStatus.Cash;
            //this.City.CityStatus.Cash = this.City.CityStatus.Cash - price;

            this.City.Budget.Spendings += price;
            CashView.Text = actualCash + "$";
            return true;
        }

        public void LoadCity(IList<user> users)
        {
            m_CityObjects = new List<ICityElement>();

            ICityService cityService = new ChannelFactory<ICityService>("BasicHttpBinding_ICityService").CreateChannel();
            //+
            AsyncCallback asyncCallBack = delegate(IAsyncResult result)
            {
                this.City = ((ICityService)result.AsyncState).EndGetPlayerCity(result);

                Dispatcher.BeginInvoke(delegate()
                {

                    CityClock.ClockTime = this.City.CityStatus.CityDate;
                    CityClock.Begin();

                    int oldcash = Convert.ToInt32(CashView.Tag);
                    int currentcash = this.City.CityStatus.Cash;

                    CashView.Text = currentcash + "$";
                    CashView.Tag = currentcash;


                    int oldpopulation = Convert.ToInt32(PopulationView.Text);
                    int currentpopulation = this.City.CityStatus.Population.Total;

                    PopulationView.Text = currentpopulation.ToString();
                    PointsView.Text = this.City.CityStatus.XP.ToString();


                    foreach (Neighbour n in this.City.Neighboures.Values)
                    {

                        FriendsListbox.NeighboursListbox.Items.Add(n);
                        //Neigbours.Add(Convert.ToInt64(n.uid), n);




                    }

                    FriendsListbox.GetNeighboursScore();




                    foreach (CityElement c in this.City.Elements)
                    {
                        Zone zone = new Zone(Type.GetType(c.CityElementDesign));


                        zone.CursorType = c.CursorType;
                        zone.ElementType = c.ElementType;
                        zone.ElementOrientation = c.ElementOrientation;
                        zone.MouseEnter += new MouseEventHandler(zone_MouseEnter);
                        zone.MouseLeave += new MouseEventHandler(zone_MouseLeave);
                        zone.SetValue(Canvas.LeftProperty, c.X);
                        zone.SetValue(Canvas.TopProperty, c.Y);
                        //zone.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(zone_MouseLeftButtonUp);
                        zone.CreateDate = c.CreateDate;
                        zone.UpdateDate = c.UpdateDate;
                        zone.X = c.X;
                        zone.Y = c.Y;
                        zone.GridColumn = c.GridColumn;
                        zone.GridRow = c.GridRow;
                        zone.ConnectionID = c.ConnectionID;
                        zone.ElementStage = CityElementStage.Building;

                        zone.init(this);


                        CityEditor.CursorHandle(zone, false, false);

                        zone.SetValue(Canvas.ZIndexProperty, (c.GridRow + 1) * (c.GridColumn + 1));

                        string thename = "Empty_" + c.GridColumn.ToString() + "_" + c.GridRow.ToString();
                        Empty empty = (Empty)MainPage.Editor.CityGrid.FindName(thename);
                        if (empty != null)
                        {

                            MainPage.Editor.CityGrid.Children.Remove(empty as UIElement);

                        }





                        //  MainPage.Editor.CityGrid.Children.Add(zone);
                        this.CityCanvas.AddCityElement(zone);

                    }

                    Cars = new List<Car>();
                    int ff = 0;
                    foreach (ICityElement c in this.CityCanvas.CityElements)
                    {

                        Zone z = (c as Zone);
                        if (z != null && z.ElementType == CityElementType.Road)
                        {
                            z.SetValue(Canvas.ZIndexProperty, ElementZindex.Road);

                            MainPage.Editor.SetRoad(z, 0);

                            if (z.ConnectionID > 0)
                            {
                                if (z.Design is Road1I)
                                    (z.Design as Road1I).SetNeighbour();

                            }
                            ff++;
                            if (ff == 4)
                            {

                                ff = 0;
                                Car car = new Car();
                                car.SetValue(Canvas.TopProperty, (double)z.Y);
                                car.SetValue(Canvas.LeftProperty, (double)z.X);
                                car.SetValue(Canvas.ZIndexProperty, ElementZindex.Car);
                                car.CityCanvas = CityCanvas;
                                Guid g = Guid.NewGuid();

                                car.Name = "Car_" + g.ToString();

                                this.CityCanvas.Canvas.Children.Add(car);


                                Cars.Add(car);


                            }
                        }
                    }

                    System.Windows.Threading.DispatcherTimer pulse = null;
                    pulse = new System.Windows.Threading.DispatcherTimer();
                    pulse.Interval = TimeSpan.FromMilliseconds(100 / MainPage.Heart.CityInterval);
                    pulse.Tick += new EventHandler(pulse_Tick);
                    pulse.Start();

                    //   SaveIndicator.Text = "City Loaded";




                    System.Windows.Threading.DispatcherTimer cityStatusTimer = new System.Windows.Threading.DispatcherTimer();
                    cityStatusTimer.Interval = new TimeSpan(0, 0, 0, 0, 10000); // 100 Milliseconds 
                    cityStatusTimer.Tick += new EventHandler(cityStatusTimer_Tick);
                    cityStatusTimer.Start();


                    SplashLogin.Visibility = Visibility.Collapsed;


                    //



                });


            };
            //   SaveIndicator.Text = "Loading City";
            cityService.BeginGetPlayerCity(this.UserID, asyncCallBack, cityService);

        }

        public void AddNeigbour(user neigbour)
        {


            long u = Convert.ToInt64(neigbour.uid);
            if (!MainPage.Heart.City.Neighboures.ContainsKey(u))
            {

                Neighbour n = new Neighbour();

                n.NeighbourId = u;
                n.Facebook_pic_square = neigbour.pic_square;
                n.Name = neigbour.name;

                if (MainPage.Heart.Neigbours == null)
                    MainPage.Heart.Neigbours = new Dictionary<long, Neighbour>();

                if (!MainPage.Heart.Neigbours.ContainsKey(u))
                    MainPage.Heart.Neigbours.Add(u, n);

                MainPage.Heart.City.Neighboures.Add(u, n);

                SaveIndicator.Text = "*";
                MainPage.Heart.SetDirty();
                this.FriendsListbox.NeighboursListbox.Items.Add(n);

                //List<long> list = new List<long>();
                //list.Add(u);

                //ICityService cityService = new ChannelFactory<ICityService>("BasicHttpBinding_ICityService").CreateChannel();
                ////+
                //AsyncCallback asyncCallBack = delegate(IAsyncResult result)
                //{



                //    Dispatcher.BeginInvoke(delegate()
                //    {


                //        //update element by connection id

                //       // Road1I elem =(Road1I)NeigboursZones[u];
                //        //elem.SetNeighbour();




                //    });


                //};
                //cityService.BeginGetNeighbours(list, asyncCallBack, cityService);




            }


        }
        #endregion

        #region City Elements


        public void RemoveCityElement(ICityElement elem)
        {
            m_CityObjects.Remove(elem);

            List<CityElement> elems = (from a in m_City.Elements
                                       where a.GridColumn == elem.GridColumn && a.GridRow == elem.GridRow
                                       select a).ToList();

            foreach (CityElement elemX in elems)
            {
                m_City.Elements.Remove(elemX);

            }

            CityCanvas.RemoveCityElement(elem as Zone);




        }

        public void AddCityElement(ICityElement elem)
        {
            //            (elem as Zone).PropertyChanged += new PropertyChangedEventHandler(CityHeart_PropertyChanged);
            m_CityObjects.Add(elem);




            CityLife.CityService.CityElement celem = new CityLife.CityService.CityElement();
            celem.CreateDate = elem.CreateDate;
            celem.UpdateDate = elem.UpdateDate;
            celem.X = elem.X;
            celem.Y = elem.Y;
            celem.GridColumn = elem.GridColumn;
            celem.GridRow = elem.GridRow;


            celem.CursorType = elem.CursorType;
            celem.ElementType = elem.ElementType;

            celem.ElementOrientation = elem.ElementOrientation;

            celem.CityElementDesign = elem.CityElementDesign.FullName;
            celem.ConnectionID = elem.ConnectionID;
            celem.Capacity = elem.Capacity;
            celem.Polution = (elem as Zone).Design.Info.Emissions;

            // celem.Pol = elem.Capacity;
            celem.ElementStage = elem.ElementStage;
            m_City.Elements.Add(celem);



            //message to finish build

            DateTime t = DateTime.Now.AddMinutes((elem as Zone).Design.Info.BuildDuration);
            GameSteps.SetStep(celem, t, CityElementStage.Completed);



        }
        #endregion


        #region Timer functions
        void pulse_Tick(object sender, EventArgs e)
        {
            foreach (Car car in Cars)
            {
                car.Drive();
            }
        }

        void cityStatusTimer_Tick(object sender, EventArgs e)
        {
            GetCityStatus();



            //proccess step messages
            //get all messages

            if (this.City.CityStages != null)
            {
                List<CityStageLink> steps = (from q in this.City.CityStages
                                             where q.StageDate <= DateTime.Now
                                             select q).ToList();


                foreach (CityStageLink l in steps)
                {
                    //update the cityElement object
                    CityElement c = (from a in this.City.Elements
                                     where a.GridRow == l.GridRow && a.GridColumn == l.GridCol
                                     select a).FirstOrDefault();
                    if (c != null)
                    {
                        c.ElementStage = l.ElementStage;
                     

                        //now find the Grid element and change it
                        string cname = "Zone_" + c.GridColumn.ToString() + "_" + c.GridRow.ToString();

                        Zone z = (Zone)MainPage.Editor.CityGrid.FindName(cname);

                        if (z != null)
                        {
                            z.Design.SetBuildStep(l.ElementStage);
                            z.ElementStage = l.ElementStage;

                            switch (l.ElementStage)
                            {
                                case CityElementStage.Completed:

                                    DateTime t = DateTime.Now.AddMinutes(z.Design.Info.MelfunctionDuration);
                                    GameSteps.SetStep(c, t, CityElementStage.Melfunctioned);
                                    break;


                            }

                        }



                    }

                    this.City.CityStages.Remove(l);

                }




            }


        }



        public void GetCityStatus()
        {
            ICityService cityService = new ChannelFactory<ICityService>("BasicHttpBinding_ICityService").CreateChannel();
            //+
            AsyncCallback asyncCallBack = delegate(IAsyncResult result)
            {
                this.City.CityStatus = ((ICityService)result.AsyncState).EndGetCityStatus(result);

                this.City.CityStatus.Cash = this.City.CityStatus.Cash - this.City.Budget.Spendings;
                Dispatcher.BeginInvoke(delegate()
                {

                    CityClock.ClockTime = this.City.CityStatus.CityDate;
                    CityClock.Begin();

                    int oldcash = Convert.ToInt32(CashView.Tag);
                    int currentcash = this.City.CityStatus.Cash;

                    CashView.Text = currentcash + "$";
                    CashView.Tag = currentcash;

                    if (oldcash < currentcash)
                        CashView.Foreground = new SolidColorBrush(Colors.Green);
                    else
                        CashView.Foreground = new SolidColorBrush(Colors.Red);


                    int oldpopulation = Convert.ToInt32(PopulationView.Text);
                    int currentpopulation = this.City.CityStatus.Population.Total;
                    if (oldpopulation < currentpopulation)
                        PopulationView.Foreground = new SolidColorBrush(Colors.Green);
                    else
                        PopulationView.Foreground = new SolidColorBrush(Colors.Red);


                    PopulationView.Text = this.City.CityStatus.Population.Total.ToString();
                    PointsView.Text = this.City.CityStatus.XP.ToString();
                });


            };
            cityService.BeginGetCityStatus(this.UserID, asyncCallBack, cityService);

        }

        private void myDispatcherTimer_Tick(object sender, System.EventArgs e)
        {
            myDispatcherTimer.Stop();


            ICityService cityService = new ChannelFactory<ICityService>("BasicHttpBinding_ICityService").CreateChannel();
            //+
            AsyncCallback asyncCallBack = delegate(IAsyncResult result)
            {
                ((ICityService)result.AsyncState).EndSaveCity(result);

                Dispatcher.BeginInvoke(delegate()
                {
                    SaveIndicator.Text = "City Saved";

                });
            };


            // SaveIndicator.Text = "Saving City";
            cityService.BeginSaveCity(m_City, asyncCallBack, cityService);

        }

        #endregion

        public void GetAppUserObjectsCompleted(IList<user> users, object state, FacebookException e)
        {

            Dispatcher.BeginInvoke(delegate()
            {
                if (users == null)
                    return;

                LoadCity(users);
                //PlayersListLoader.IsBusy = false;
            });

        }

        #region Element information panel


        public void zone_MouseLeave(object sender, MouseEventArgs e)
        {
            (sender as Zone).UnHilight();
            ElementInformationTimer.Stop();
        }

        public void zone_MouseEnter(object sender, MouseEventArgs e)
        {


            (sender as Zone).Hilight();
            UIElement u = (sender as UIElement);
            if (!MainPage.Editor.Dragging)
            {

                GeneralTransform objGeneralTransform = u.TransformToVisual(Application.Current.RootVisual as UIElement);
                Point point = e.GetPosition(WindowCityCanvas);




                ElementInformation.SetValue(Canvas.TopProperty, Convert.ToDouble(point.Y));
                ElementInformation.SetValue(Canvas.LeftProperty, Convert.ToDouble(point.X));

                if (ElementInformation.CityElement != sender as ICityElement)
                {

                    ElementInformation.CityElement = sender as ICityElement;

                    //ElementInformation.Margin = t;
                    ElementInformationTimer.Start();
                }
                else
                {
                    ElementInformation.SetVisible();

                }

            }
            u.ReleaseMouseCapture();






            //double years =Math.Abs( (( (sender as Zone).CreateDate - this.m_City.CityStatus.CityDate).Days / 365));
            //(  ElementInformation.FindName("ElementText") as TextBlock).Text="Built at:" +  (sender as Zone).CreateDate.ToString("dd.M.yyyy");
            //(ElementInformation.FindName("ElementText") as TextBlock).Text += Environment.NewLine;
            //(ElementInformation.FindName("ElementText") as TextBlock).Text += "Age:" + years;






        }

        void ElementInformationTimer_Tick(object sender, EventArgs e)
        {
            ElementInformation.Show();
            ElementInformationTimer.Stop();
        }


        #endregion


    }
}